#include <memory>

#include <ballade/smartclient/client.h>

namespace Ballade
{
	namespace SmartClient
	{
		// Constructor and Deconstructor
		Client::Client()
		{
			initialize("", 0);
		}

		Client::Client(const char *ipaddr, const unsigned short port)
		{
			initialize(ipaddr, port);
		}
		// End of Constructor and Deconstructor

		// Public
		const char *Client::getIPAddress() const
		{
			return _socket.getIPAddress();
		}

		const unsigned short& Client::getPort() const
		{
			return _socket.getPort();
		}

		void Client::setIPAddress(const char *ipaddr)
		{
			_socket.setIPAddress(ipaddr);
		}

		void Client::setPort(const unsigned short port)
		{
			_socket.setPort(port);
		}
		
		void Client::addListener(Listener *listener)
		{
			_dipatcher.registerListener(listener);
		}

		void Client::connect(const char *ipaddr, const unsigned short port)
		{
			setIPAddress(ipaddr);
			setPort(port);
			connect();
		}

		void Client::connect()
		{
			if(isConnected()) close();
			_socket.connect();

			startReaderThread();
		}

		void Client::close()
		{
			stopReaderThread();

			_socket.close();
		}

		const bool Client::isConnected() const
		{
			return _socket.isConnected() && !_readerThread->isTerminated();
		}

		void Client::send(const char *name, const void *data)
		{
			Header &header = _headerCreater->createHeader(name);
			_socket.getOutputStream().write((char *)header.getRawValue(), header.getLength());
			_socket.getOutputStream().write((char *)data, header.getBodyLength());
		}

		void Client::setHeaderCreater(HeaderCreater *creater)
		{
			_headerCreater = creater;
		}
		// End of Public

		// Protected
		void Client::startReaderThread()
		{
			_readerThread = new ReaderThread(_socket, _dipatcher);
			_readerThread->setHeaderCreater(_headerCreater);
			_readerThread->start();
		}

		void Client::stopReaderThread()
		{
			if(_readerThread)
			{
				_readerThread->stop();
				_readerThread = NULL;
			}
		}

		// End of Protected

		// Private
		void Client::initialize(const char *ipaddr, const unsigned short port)
		{
			setIPAddress(ipaddr);
			setPort(port);

			_headerCreater = NULL;
			_readerThread = NULL;
		}
		// End of Private
	}
}